package io.coderyeah.basic.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.coderyeah.basic.Result;
import io.coderyeah.basic.constant.Constants;
import io.coderyeah.basic.dto.PhoneCodeDTO;
import io.coderyeah.basic.exception.BusinessException;
import io.coderyeah.basic.service.VerifyCodeService;
import io.coderyeah.basic.util.VerifyCodeUtils;
import io.coderyeah.user.constant.VerifyCodeConstants;
import io.coderyeah.user.domain.User;
import io.coderyeah.user.domain.WxUser;
import io.coderyeah.user.mapper.UserMapper;
import io.coderyeah.user.mapper.WxUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VerifyCodeServiceImpl implements VerifyCodeService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WxUserMapper wxUserMapper;

    @Override
    public Result getImgCode(String key) {
        // 获取随机验证码长度为4
        final String code = VerifyCodeUtils.generateVerifyCode(4);
        // 将验证码的值存入redis中 有效期五分钟
        stringRedisTemplate.opsForValue().set("cache:code:image:" + key, code, 5L, TimeUnit.MINUTES);
        // 把验证码的值合并到图片，设置宽度和高度 使用Base64编码。并返回base64编码的字符串
        return Result.success(VerifyCodeUtils.verifyCode(115, 40, code));
    }

    @Override
    public Result getPhoneCode(PhoneCodeDTO phoneCodeDTO) {
        final String phone = phoneCodeDTO.getPhone();
        final String InputImageCode = phoneCodeDTO.getImageCode();
        final String imageCodeKey = phoneCodeDTO.getImageCodeKey();
        // 1.判断参数是否为空
        if (StrUtil.isBlank(phone)) {
            // 抛出异常
            throw new BusinessException("电话号码不能为空");
        }
        if (StrUtil.isBlank(InputImageCode)) {
            // 抛出异常
            throw new BusinessException("图形验证码不能为空不能为空");
        }
        // 2.判断图形验证码是否过期 正确
        final String imageCode = stringRedisTemplate.opsForValue().get("cache:code:image:" + imageCodeKey);
        if (StrUtil.isBlank(imageCode)) {
            // 过期了
            throw new BusinessException("图形验证码已过期,请重新输入！");
        }
        // 判断是否一致 忽略大小写
        if (!InputImageCode.equalsIgnoreCase(imageCode)) {
            throw new BusinessException("图片验证码错误,请重新输入！");
        }
        // 3. 通过号码判断用户是否已经注册
        final User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhone, phone));
        if (user != null) {
            // 用户已经存在
            throw new BusinessException("该手机号码已被注册过,请您直接登录...");
        }
        // 4.从redis获取短信验证码
        // 用来存储短信验证码  redis中存储的值是 【短信验证码:时间戳】
        String code = null;
        final String value = stringRedisTemplate.opsForValue().get(Constants.USER_REGISTER_PHONE_PREFIX + phone);
        if (value != null) { // 没有过期
            // 判断时间是否过期
            final long oldTime = Long.parseLong(value.split(":")[1]);
            // 一分钟之内不允许频繁操作
            if ((System.currentTimeMillis() - oldTime) <= 1000 * 60) {// 没过重发时间
                throw new BusinessException("操作频繁,请稍后再试!");
            } else {
                code = value.split(":")[0];
            }
        } else {// 过期了
            // 生成验证码
            code = String.valueOf(RandomUtil.randomNumbers(6));
        }
        // 存入redis 有效期3分钟
        stringRedisTemplate.opsForValue().set("user:register:" + phone, code + ":" + System.currentTimeMillis(), 3L, TimeUnit.MINUTES);
        // 发送验证码短信
//        SmsUtils.sendSms(phone, "您的验证码是" + code + ",请及时使用有限期为3分钟");
        log.info("=========您的验证码是:{}=========", code);
        return Result.success("获取验证码成功【" + code + "】");
    }

    @Override
    public void binderSmsCode(PhoneCodeDTO codeDTO) {
        final String phone = codeDTO.getPhone();
        if (StrUtil.isBlank(phone)) {
            throw new BusinessException("手机号码不能为空");
        }
        // 因为微信扫码登录需要关联手机号码 判断手机号是否已经绑定微信号
        final User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhone, phone));
        // 用户存在
        if (user != null) {
            final WxUser wxUser = wxUserMapper.selectOne(new LambdaQueryWrapper<WxUser>().eq(WxUser::getUserId, user.getId()));
            if (wxUser != null) {
                throw new BusinessException("手机号已经绑定其它微信账号,请直接登录...");
            }
        }
        final String value = stringRedisTemplate.opsForValue().get(VerifyCodeConstants.PHONE_CODE + phone);
        String code = null;
        if (value != null) {// 验证码还未过期
            //判断是否过了重发时间
            final long oldTime = Long.parseLong((value.split(":")[1]));
            if ((System.currentTimeMillis() - oldTime) <= 60) {//间隔时间未超过一分钟
                throw new BusinessException("操作频繁,请稍后再试!");
            } else {
                code = value.split(":")[0];
            }
        } else {
            // 生成验证码
            code = RandomUtil.randomNumbers(6);
        }
        stringRedisTemplate.opsForValue().set(VerifyCodeConstants.PHONE_CODE + phone, code, 3L, TimeUnit.MINUTES);
        log.info("授权短信验证码:{}", code);
    }
}
